package edu.ncsu.csc;

import java.io.IOException;
import java.util.Timer;

import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;

import com.sun.spot.peripheral.Spot;
import com.sun.spot.peripheral.radio.RadioFactory;
import com.sun.spot.sensorboard.EDemoBoard;
import com.sun.spot.sensorboard.peripheral.ISwitch;
import com.sun.spot.sensorboard.peripheral.LEDColor;
import com.sun.spot.util.IEEEAddress;
import com.sun.spot.util.Queue;
import com.sun.spot.util.Utils;
import com.sun.squawk.Isolate;

import edu.ncsu.csc.sensors.GroWeatherHumiditySensor;
import edu.ncsu.csc.sensors.GroWeatherThermometer;
import edu.ncsu.csc.sensors.GroWeatherWindDirectionSensor;
import edu.ncsu.csc.sensors.GroWeatherWindSpeedSensor;
import edu.ncsu.csc.sensors.SPOTAccelerometer;
import edu.ncsu.csc.sensors.StrainGaugeSensor;

/**
 * The main entry point for the SensorSPOT app. Instantiates the various components, connects them together,
 * waits for the user to press the left switch, then terminates.
 * 
 * (This program should strobe the LEDs green back and forth soon after startup; if not, there is probably a bug :D)
 * 
 * @author David A. Boyuka, II
 */
public class SensorSPOT extends MIDlet {
	/** Time delay between sample, in milliseconds */
	private static final long ACCELEROMETER_SAMPLE_INTERVAL = 30;
	private static final long TEMPERATURE_SENSOR_SAMPLE_INTERVAL = 1500;
	private static final long HUMIDITY_SENSOR_SAMPLE_INTERVAL = 1500;
	private static final long WIND_SPEED_SAMPLE_INTERVAL = 2250;
	private static final long WIND_DIRECTION_SAMPLE_INTERVAL = 2250;
	private static final long STRAIN_GAUGE_SAMPLE_INTERVAL = 100;

	private static final int SENSOR_TYPES = 8;
	private static final int MAX_SENSORS = 8;

	private Queue dgQueue;

	private RadioManager radioMgr;
	private Timer slowTimer;
	private Timer fastTimer;

	private int get_spot_id()
	{
		String our_address = IEEEAddress.toDottedHex(RadioFactory.getRadioPolicyManager().getIEEEAddress());
		for(int k = 0; k < MACList.mac_list.length; k++)
		{
			if(our_address.equals(MACList.mac_list[k]))
				return k;
		}
		return -1;
	}

	//returns -1 on problem

	private byte get_sensor_id(int mac_id, int sensor_slot)
	{
		if(mac_id > 31)
			return -1;
		byte result = (byte)(mac_id << 3);
		if(sensor_slot > 7)
			return -1;
		result += sensor_slot;
		return result;
	}

	void pickSensorsManually()
	{
		
		ISwitch[] switches = EDemoBoard.getInstance().getSwitches();
		int mac_id = get_spot_id();

		int time_out = 10000;
		boolean finished = false;
		for(int k =0 ; k < MAX_SENSORS && !finished; k++)
		{
			int time_passed = 0;
			int selected_sensor = 0;
			LEDHelper.disableAll();
			LEDHelper.enable_byte_binary((byte)(selected_sensor + 1));
			while (switches[0].isOpen())
			{
				if(switches[1].isClosed())
				{
					LEDHelper.disableAll();//(selected_sensor);
					selected_sensor = (selected_sensor + 1)  % SENSOR_TYPES;
					LEDHelper.setColorAll(128,128,128);
					LEDHelper.enable_byte_binary((byte)(selected_sensor + 1));
					time_passed = 0;
				}
				Utils.sleep(120);
				time_passed += 130;
				if(time_passed >= time_out)
				{
					finished = true;
					break;
				}
				else
				{
					int brightness = (int)(128 - 128 * ((double)time_passed/time_out));
					brightness = (int)(brightness/256.0 * brightness);
					LEDHelper.setColorAll(brightness, brightness, brightness);
				}
			}
			if(!finished)
			{

				LEDHelper.setColorAll(128,128,128);
				LEDHelper.flash(300);
				// sensor id setup

				byte sensor_id = get_sensor_id(mac_id, k);

				// sensor setup
				initSensorTask(selected_sensor, sensor_id);
				Utils.sleep(100);
			}
		}
	}

	private void pickSensorsFromConfig() throws IOException {
		Configuration conf = Configuration.loadFromSystemProperties();
		
		byte spotID = (byte)get_spot_id();
		
		for (int i = 0; i < conf.getSensorTypes().length; i++) {
			byte sensorID = get_sensor_id(spotID, i);
			initSensorTask(conf.getSensorTypes()[i], sensorID);
		}
		
		LEDHelper.setColorAll(LEDColor.BLUE);
		LEDHelper.enable_byte_binary((byte)(spotID + 1));
		try { Thread.sleep(750); } catch (InterruptedException ie) {}
		LEDHelper.setColorAll(LEDColor.WHITE);
		for (int i = 0; i < conf.getSensorTypes().length; i++) {
			LEDHelper.disableAll();
			LEDHelper.enable_byte_binary((byte)(conf.getSensorTypes()[i] + 1));
			try { Thread.sleep(750); } catch (InterruptedException ie) {}
		}
		LEDHelper.disableAll();
	}
	
	private void initSensorTask(int selected_sensor, byte sensor_id) {
		SensorTask sensor_task;
		long sensor_interval;
		boolean isFast;
		switch(selected_sensor)
		{
			case 0:	// accelerometer x
				sensor_task = new SensorTask(new SPOTAccelerometer('x'), sensor_id, radioMgr, dgQueue);
				sensor_interval = ACCELEROMETER_SAMPLE_INTERVAL;
				isFast = true;
				break;
			case 1:	// accelerometer y
				sensor_task = new SensorTask(new SPOTAccelerometer('y'), sensor_id, radioMgr, dgQueue);
				sensor_interval = ACCELEROMETER_SAMPLE_INTERVAL;
				isFast = true;
				break;
			case 2:	// accelerometer z
				sensor_task = new SensorTask(new SPOTAccelerometer('z'), sensor_id, radioMgr, dgQueue);
				sensor_interval = ACCELEROMETER_SAMPLE_INTERVAL;
				isFast = true;
				break;
			case 3: // groweather themometer
				sensor_task = new SensorTask(new GroWeatherThermometer(), sensor_id, radioMgr, dgQueue);
				sensor_interval = TEMPERATURE_SENSOR_SAMPLE_INTERVAL;
				isFast = false;
				break;
			case 4: // groweather humidity sensor
				sensor_task = new SensorTask(new GroWeatherHumiditySensor(), sensor_id, radioMgr, dgQueue);
				sensor_interval = HUMIDITY_SENSOR_SAMPLE_INTERVAL;
				isFast = false;
				break;
			case 5: // groweather wind speed sensor
				sensor_task = new SensorTask(new GroWeatherWindSpeedSensor(), sensor_id, radioMgr, dgQueue);
				sensor_interval = WIND_SPEED_SAMPLE_INTERVAL;
				isFast = false;
				break;
			case 6: // groweather wind direction sensor
				sensor_task = new SensorTask(new GroWeatherWindDirectionSensor(), sensor_id, radioMgr, dgQueue);
				sensor_interval = WIND_DIRECTION_SAMPLE_INTERVAL;
				isFast = false;
				break;
			case 7: // strain gauge on A0 
				sensor_task = new SensorTask(new StrainGaugeSensor(EDemoBoard.A0), sensor_id, radioMgr, dgQueue);
				sensor_interval = STRAIN_GAUGE_SAMPLE_INTERVAL;
				isFast = true;
				break;
			case 8: // strain gauge on A1 
				sensor_task = new SensorTask(new StrainGaugeSensor(EDemoBoard.A1), sensor_id, radioMgr, dgQueue);
				sensor_interval = STRAIN_GAUGE_SAMPLE_INTERVAL;
				isFast = true;
				break;
			default:
				throw new IllegalArgumentException("Invalid sensor type: " + selected_sensor);
		}
		// wait 15 seconds before actually sampling so that radio LEDs
		// don't interfere with the selection LEDs

		if (isFast) fastTimer.scheduleAtFixedRate(sensor_task, 15000,sensor_interval);
		else 		slowTimer.scheduleAtFixedRate(sensor_task, 15000,sensor_interval);
	}

	protected void startApp() throws MIDletStateChangeException {
		Spot.getInstance().getSleepManager().disableDeepSleep();
		
		// Set up shared Queue for Datagrams
		dgQueue = new Queue();

		// Set up RadioManager

		radioMgr = setUpRadioManager(dgQueue);
		radioMgr.start();

		// Make a new Timer

		slowTimer = new Timer();
		fastTimer = new Timer();

		// manually select Sensors,mMake new TimerTasks and schedule them

		ISwitch sw = EDemoBoard.getInstance().getEDemoController().getSwitches()[0];
		if (sw.isClosed()) pickSensorsManually();
		else {
			try {
				pickSensorsFromConfig();
			} catch (IOException ioe) {
				LEDHelper.setColorAll(LEDColor.RED);
				LEDHelper.flash(500);
				pickSensorsManually();
			}
		}
		
	//	SensorTask sensor1 = new SensorTask(new SPOTAccelerometer(), (byte)0, radioMgr, dgQueue);
	//	SensorTask sensor2 = new SensorTask(new SPOTLightSensor(), (byte)1, radioMgr, dgQueue);
	//	timer.schedule(sensor1, 100, ACCELEROMETER_SAMPLE_INTERVAL);
	//	timer.schedule(sensor2, 100, LIGHT_SENSOR_SAMPLE_INTERVAL);

		// Strobe back and forth green to indicate set up is complete
		LEDHelper.setColorAll(LEDColor.GREEN);
		LEDHelper.strobeRight(500);
		LEDHelper.strobeLeft(500);


		/* MOVED THIS DOWN HERE BECAUSE LEDS INTERFERE WITH SELECTION PROCESS */

		// Wait for someone to press the left switch, then quit
		EDemoBoard.getInstance().getEDemoController().getSwitches()[0].waitForChange();

		shutdown();
		
		// Strobe back and forth red to indicate that the SensorSPOT is shutting down
		LEDHelper.setColorAll(LEDColor.RED);
		LEDHelper.strobeLeft(500);
		LEDHelper.strobeRight(500);
		notifyDestroyed(); // This is like System.exit()
	}

	private RadioManager setUpRadioManager(Queue dgQueue) {
		RadioManager radioMgr;
		
		try {
			radioMgr = new RadioManager(dgQueue);
		} catch (IOException ioe) {
			ioe.printStackTrace();
			notifyDestroyed(); // This is like System.exit()
			return null;
		}
		
		return radioMgr;
	}
	
	private void shutdown() {
		slowTimer.cancel();
		fastTimer.cancel();
		radioMgr.interrupt();
	}
	
	protected void pauseApp() {}

	protected void destroyApp(boolean unconditional) throws MIDletStateChangeException {
		shutdown();
	}
}
